# 03 Rust复杂数据定义 ## 3.1 Rust 结构体(Struct)核心概念与用法笔记 在 Rust 中,结构体(`struct`)用于创建自定义的数据类型,将多项相关联的值打包在一起。配合 `impl` 块(实现方法)和组合(Composition),你可以构建出结构清晰、职责分明的面向对象风格或函数式风格的代码架构。 --- ### 一、 定义结构体(Struct Definitions) Rust 支持三种形式的结构体,适应不同的数据组织场景: #### 1. 具名字段结构体(C-like Structs) 最常用的形式,每个字段都有明确的名字和类型。 ```rust ##[derive(Debug)] struct ServerConfig { host: String, port: u16, timeout_seconds: u64, } ``` #### 2. 元组结构体(Tuple Structs) 字段没有名字,只有类型顺序。适合给基本类型起一个“强类型别名”,避免混淆。 ```rust struct Point(i32, i32); struct Color(u8, u8, u8); ``` #### 3. 单元结构体(Unit-like Structs) 没有任何字段,类似于 `()`。通常用于实现某些特定特征(Trait)而不需要存储状态。 ```rust struct EmptyMarker; ``` --- ### 二、 实现结构体中的方法(Methods & Associated Functions) 通过 `impl` 块,可以为结构体绑定函数。Rust 将其分为两类: 1. **关联函数(Associated Functions / Constructors)**:类似其他语言的“静态方法”,通常用于构造实例(惯例命名为 `new`)。**注意:它没有 `self` 参数。** 2. **方法(Methods)**:需要操作具体实例的函数。它们的第一个参数必须是 `self` 的某种形态(`self`、`&self` 或 `&mut self`)。 ```rust impl ServerConfig { // 1. 关联函数:用于构造实例 fn new(host: String, port: u16) -> Self { Self { host, port, timeout_seconds: 30, // 默认超时时间 } } // 2. 方法(借用不可变实例):只读取数据 fn address(&self) -> String { format!("{}:{}", self.host, self.port) } // 3. 方法(借用可变实例):修改内部状态 fn set_timeout(&mut self, timeout: u64) { self.timeout_seconds = timeout; } } ``` **使用示例:** ```rust fn main() { // 调用关联函数创建实例(必须是 mut 才能调用可变方法) let mut config = ServerConfig::new("127.0.0.1".to_string(), 8080); println!("Server address: {}", config.address()); // 读取 config.set_timeout(60); // 修改 } ``` --- ### 三、 通过组合产生新的结构体(Composition) Rust 强烈推荐“组合优于继承”(Composition over Inheritance)。通过将已有的结构体作为新结构体的字段,可以轻松构建出更复杂、层级化的数据结构。 #### 1. 包含具名字段的组合 当一个大系统由多个子模块配置组成时,直接组合: ```rust ##[derive(Debug)] struct DatabaseConfig { url: String, max_connections: u32, } ##[derive(Debug)] struct AppConfig { name: String, server: ServerConfig, // 组合了前面定义的 ServerConfig database: DatabaseConfig, // 组合了 DatabaseConfig } ``` **实例化与访问:** ```rust let app_cfg = AppConfig { name: "MyService".to_string(), server: ServerConfig::new("0.0.0.0".to_string(), 3000), database: DatabaseConfig { url: "postgres://localhost:5432/db".to_string(), max_connections: 10, }, }; // 通过点号链式访问内层结构体的字段 println!("Database max conn: {}", app_cfg.database.max_connections); ``` #### 2. 字段初始化简写与结构体更新语法(Struct Update Syntax) 当局部变量名与字段名相同时,可以直接简写;同时可以用 `..` 语法基于已有实例快速派生新实例: ```rust let host = "192.168.1.100".to_string(); let port = 9000; // 简写初始化 let base_config = ServerConfig { host, port, timeout_seconds: 10, }; // 结构体更新语法:复用 base_config 的 host 和 timeout,只修改 port let custom_config = ServerConfig { port: 8081, ..base_config }; ``` --- ### 四、 核心优势总结 * **零开销抽象**:Rust 的组合在内存中是平铺布局的(没有隐藏的虚表或指针开销),性能等价于 C 语言的手动内存布局。 * **清晰的借用控制**:通过 `&self`、`&mut self` 和 `self`,编译器在编译期就能严格杜绝数据竞争和非法的状态修改。 ## 3.2 Rust 枚举(Enum)核心概念与用法笔记 在 Rust 中,枚举(`enum`)远比传统语言(如 C/C++、Java)中的枚举强大。它们是**代数数据类型(Algebraic Data Types)**,不仅能表示一组离散的值,还能携带丰富的数据,是构建强类型、安全架构的基石。 --- ### 一、 枚举的三种形态(变体 Variants) Rust 枚举的每个变体(Variant)都可以独立携带不同类型和结构的数据。主要分为三种形态: #### 1. 单元变体(Unit Variants) 不带任何数据,类似于传统的 C 风格枚举。适用于表示纯粹的状态或标签。 ```rust enum Direction { North, South, East, West, } ``` #### 2. 元组变体(Tuple Variants) 包含按位置排序的匿名数据,类似于元组。 ```rust enum Message { Quit, // 类似单元变体 Move { x: i32, y: i32 }, // (注意:此处示例混淆了结构体,下面修正) Write(String), // 包含一个 String ChangeColor(i32, i32, i32), // 包含三个 i32 } ``` *(修正上面的注释)*: * `Write(String)` 和 `ChangeColor(i32, i32, i32)` 属于**元组变体**。 #### 3. 结构体变体(Struct Variants) 包含具名字段,类似于标准的 `struct`。 ```rust enum WorkerCount { Explicit(usize), Ignored { value: String, used: usize }, // 具名字段结构体变体 } ``` --- ### 二、 如何构造与实例化枚举 带数据的枚举变体就像是一个**可以传入参数并实例化的工厂或类型**: ```rust // 构造一个带有字段的 Ignored 变体实例 let count = WorkerCount::Ignored { value: "invalid_env".to_string(), used: 4, }; ``` --- ### 三、 如何使用与模式匹配(Match) Rust 强制使用 `match` 或 `if let` 对枚举进行穷尽式匹配(Exhaustive Matching),这保证了所有可能的分支都不会被漏掉。 ```rust match count { WorkerCount::Explicit(n) => { println!("使用用户指定的线程数: {n}"); } WorkerCount::Ignored { value, used } => { println!("环境变量格式错误: '{}', 已降级使用默认值: {}", value, used); } } ``` --- ### 四、 Rust 枚举的两大王牌:`Option` 与 `Result` Rust 标准库中最常用的两个泛型枚举: 1. **`Option`**:用来替代其他语言中的 `null`。 ```rust pub enum Option { Some(T), None, } ``` 1. **`Result`**:用来处理可恢复的错误。 ```rust pub enum Result { Ok(T), Err(E), } ``` --- ### 五、 枚举的高级特性与优势 * **零成本抽象(Zero-cost abstractions)**:Rust 编译器会对枚举进行内存优化(例如利用指针不为零的特性,让 `Option` 的内存大小和原始类型完全一致)。 * **携带行为**:可以通过 `impl` 块为枚举定义方法、实现特征(Traits)。 * **类型安全**:将状态和与状态相关的数据绑定在一起,使得非法的状态组合在编译期就无法产生。